#include "idt.h"
#include "timer.h"
#include <stdio.h>

static s_idt IDT[256];

void init_idt_at_index(int index, t_uint32 offset)
{
  IDT[index].offset_low = offset;
  IDT[index].segment_selector = 0x8;
  IDT[index].flags1 = 0;
  IDT[index].flags2 = 0x8f;
  IDT[index].offset_high = offset >> 16;
}

void handler_stuck(const char* str)
{
  printf("%s\n", str);

  __asm__ ("cli\n\t");

  while (1)
    __asm__ ("hlt\n\t");
}

void div_zero_exception()
{
  handler_stuck("Exception: Division by 0");
}

void debug_exception()
{
  handler_stuck("Debug Exception");
}

void non_maskable_exception()
{
  handler_stuck("Non Maskable Exception");
}

void breakpoint_exception()
{
  handler_stuck("Breakpoint Exception");
}

void overflow_exception()
{
  handler_stuck("Overflow Exception");
}

void bounds_exception()
{
  handler_stuck("Bounds Exception");
}

void invalid_opcode_exception()
{
  handler_stuck("Invalid OpCode Exception");
}

void coproc_not_available_exception()
{
  handler_stuck("CoProcessor not Available exception");
}

void double_fault_exception()
{
  handler_stuck("Double Fault Exception");
}

void keypress_exception()
{
  handler_stuck("KeyPress Exception");
}

void default_exception ()
{
  printf("Exception occured\n");
}

void init_idt()
{
  int i;
  s_idtr idtr;


  for (i = 0; i <= 255; ++i)
    init_idt_at_index(i, (unsigned int) keypress_exception);

  init_idt_at_index(0, (t_uint32) div_zero_exception);
  init_idt_at_index(1, (unsigned int) debug_exception);
  init_idt_at_index(2, (unsigned int) non_maskable_exception);
  init_idt_at_index(3, (unsigned int) breakpoint_exception);
  init_idt_at_index(4, (unsigned int) overflow_exception);
  init_idt_at_index(5, (unsigned int) bounds_exception);
  init_idt_at_index(6, (unsigned int) invalid_opcode_exception);
  init_idt_at_index(7, (unsigned int) coproc_not_available_exception);
  init_idt_at_index(8, (unsigned int) double_fault_exception);
  init_idt_at_index(0x21, (unsigned int) keypress_exception);
  init_idt_at_index(0x20, (unsigned int) keypress_exception);
  init_idt_at_index(0xA0, (unsigned int) keypress_exception);
  init_idt_at_index(0xA1, (unsigned int) keypress_exception);
  init_idt_at_index(0x64, (unsigned int) keypress_exception);
  init_idt_at_index(0x60, (unsigned int) keypress_exception);
  init_idt_at_index(9, (unsigned int) keypress_exception);
  init_idt_at_index(10, (unsigned int) keypress_exception);
  init_idt_at_index(0x40, (unsigned int)manage_time);
  idtr.lim = 256 * (sizeof (s_idt)) - 1;
  idtr.idt = (unsigned int) &IDT;

  __asm__ ("lidt %0"
	   :
	   : "m" (idtr)
	   :);


  __asm__ ("movl %cr0, %eax\n\t"
	   "or   $0x1, %eax\n\t"
	   "movl %eax, %cr0\n\t"
	   "movw $0x10, %ax\n\t"
	   "movw %ax, %ds\n\t"
	   "movw %ax, %ss\n\t"
	   "push $0x08\n\t"
	   "push $1f\n\t"
	   "lret\n\t"
	   "1:\n\t");
}
